package com.dz.scrm.utils;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Function;

/**
 * Created by pengfei.wang on 2018/11/30.
 * 定时器工具类
 * timer 延迟多少毫秒后 执行操作
 * interval 定时多少毫秒 执行操作
 * timeAndInterval 延迟多少毫秒后 定时多少毫秒 执行操作
 * 注意：执行操作在主线程
 */

public class TimerUtils {
    private static final String TAG = "TimerUtils";
    private static TimerUtils timerUtils = null;
    private Map<String, Disposable> mDisposables = new ConcurrentHashMap<>();

    public static TimerUtils getInstance() {
        synchronized (TimerUtils.class) {
            if (timerUtils == null) {
                timerUtils = new TimerUtils();
            }
        }
        return timerUtils;
    }

    /**
     * milliseconds毫秒后执行next操作
     *
     * @param milliseconds
     * @param next
     */
    public void timer(final String key, long milliseconds, final TimerDoNext next) {
        Observable.timer(milliseconds, TimeUnit.MILLISECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<Long>() {
                    @Override
                    public void onSubscribe(@NonNull Disposable disposable) {
                        if (mDisposables != null) {
                            if (mDisposables.containsKey(key)) {
                                Disposable tempDisposable = mDisposables.get(key);
                                //定时器取消
                                if (tempDisposable != null && !tempDisposable.isDisposed()) {
                                    tempDisposable.dispose();
                                }
                                mDisposables.remove(key);
                            }
                            mDisposables.put(key, disposable);
                        } else {
                            mDisposables = new ConcurrentHashMap<>();
                            mDisposables.put(key, disposable);
                        }
                    }

                    @Override
                    public void onNext(@NonNull Long number) {
                        if (next != null) {
                            next.doNext();
                        }
                    }

                    @Override
                    public void onError(@NonNull Throwable e) {
                        //取消订阅
                        cancel(key);
                    }

                    @Override
                    public void onComplete() {
                        //取消订阅
                        cancel(key);
                    }
                });
    }


    /**
     * 每隔milliseconds毫秒后执行next操作
     *
     * @param milliseconds
     * @param next
     */
    public void interval(final String key, long milliseconds, final TimerDoNext next) {
        Observable.interval(milliseconds, TimeUnit.MILLISECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<Long>() {
                    @Override
                    public void onSubscribe(@NonNull Disposable disposable) {
                        if (mDisposables != null) {
                            if (mDisposables.containsKey(key)) {
                                Disposable tempDisposable = mDisposables.get(key);
                                //定时器取消
                                if (tempDisposable != null && !tempDisposable.isDisposed()) {
                                    tempDisposable.dispose();
                                }
                                mDisposables.remove(key);
                            }
                            mDisposables.put(key, disposable);
                        }else {
                            mDisposables = new ConcurrentHashMap<>();
                            mDisposables.put(key, disposable);
                        }
                    }

                    @Override
                    public void onNext(@NonNull Long number) {
                        if (next != null) {
                            next.doNext();
                        }
                    }

                    @Override
                    public void onError(@NonNull Throwable e) {
                        //取消订阅
                        cancel(key);
                    }

                    @Override
                    public void onComplete() {
                        //取消订阅
                        cancel(key);
                    }
                });
    }

    /**
     * 每隔milliseconds毫秒后执行next操作
     * finishMilliseconds 定时时间
     *
     * @param milliseconds
     * @param next
     */
    public void intervalFinish(final String key, final long milliseconds, final long finishMilliseconds, final TimerNextToFinish next) {
        Observable.interval(0, milliseconds, TimeUnit.MILLISECONDS)
                .map(new Function<Long, Long>() {
                    @Override
                    public Long apply(Long aLong) throws Exception {
                        long time = aLong * milliseconds;
                        return time;
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<Long>() {
                    @Override
                    public void onSubscribe(@NonNull Disposable disposable) {
                        if (mDisposables != null) {
                            mDisposables.put(key, disposable);
                        }
                    }

                    @Override
                    public void onNext(@NonNull Long number) {
                        if (number < finishMilliseconds) {
                            if (next != null) {
                                next.doNext(number);
                            }
                        } else {
                            if (next != null) {
                                next.finish();
                            }
                            cancel(key);
                        }

                    }

                    @Override
                    public void onError(@NonNull Throwable e) {
                        //取消订阅
                        cancel(key);
                    }

                    @Override
                    public void onComplete() {
                        //取消订阅
                        cancel(key);
                    }
                });
    }

    /**
     * 每隔milliseconds1毫秒后定时milliseconds2执行next操作
     *
     * @param milliseconds1 延迟毫秒
     * @param milliseconds2 定时毫秒
     * @param next
     */
    public void timeAndInterval(final String key, long milliseconds1, long milliseconds2, final TimerDoNext next) {
        Observable.timer(milliseconds1, TimeUnit.MILLISECONDS)
                .interval(milliseconds2, TimeUnit.MILLISECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<Long>() {
                    @Override
                    public void onSubscribe(@NonNull Disposable disposable) {
                        if (mDisposables != null)
                            mDisposables.put(key, disposable);
                    }

                    @Override
                    public void onNext(@NonNull Long number) {
                        if (next != null) {
                            next.doNext();
                        }
                    }

                    @Override
                    public void onError(@NonNull Throwable e) {
                        //取消订阅
                        cancel(key);
                    }

                    @Override
                    public void onComplete() {
                        //取消订阅
                        cancel(key);
                    }
                });
    }

    /**
     * 每隔milliseconds毫秒后执行next操作
     * finishMilliseconds 定时时间
     *
     * @param next
     */
    public void threadChange(final String key, final ThreadChangeToMain next) {
        Observable.create(new ObservableOnSubscribe<Long>() {

            @Override
            public void subscribe(ObservableEmitter<Long> emitter) throws Exception {
                if (next != null) {
                    next.newThreadDo();
                }
                emitter.onNext(1L);
                emitter.onComplete();
            }
        })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<Long>() {
                    @Override
                    public void onSubscribe(@NonNull Disposable disposable) {
                        if (mDisposables != null) {
                            mDisposables.put(key, disposable);
                        }
                    }

                    @Override
                    public void onNext(@NonNull Long number) {
                        if (next != null) {
                            next.finish();
                        }
                        cancel(key);
                    }

                    @Override
                    public void onError(@NonNull Throwable e) {
                        //取消订阅
                        cancel(key);
                    }

                    @Override
                    public void onComplete() {
                        //取消订阅
                        cancel(key);
                    }
                });
    }

    /**
     * 取消订阅
     */
    public void cancel(String key) {
        if (mDisposables != null && mDisposables.containsKey(key)) {
            Disposable disposable = mDisposables.get(key);
            //定时器取消
            if (disposable != null && !disposable.isDisposed()) {
                disposable.dispose();
                mDisposables.remove(key);
            }
        }
    }

    /**
     * 全部取消订阅
     */
    public void cancelAllTimes() {
        if (mDisposables == null) return;
        //遍历map中的键
        for (String key : mDisposables.keySet()) {
            cancel(key);
        }
        mDisposables.clear();
        mDisposables = null;
    }

    //定时任务
    public interface TimerDoNext {
        void doNext();
    }

    //有结束的任务
    public interface TimerNextToFinish {
        void doNext(Long number);

        void finish();
    }

    //有结束的任务
    public interface ThreadChangeToMain {
        void newThreadDo();

        void finish();
    }
}
